'''
Created on 23/03/2009

@author: eh01
'''
from yarra.datastore.dso import DSO, DSOUpdateException
from yarra.datastore.dst import DST
import unittest


class DSOTest(unittest.TestCase):


    def setUp(self):
        pass


    def tearDown(self):
        pass


    def test_to_xml(self):
        """ Test marshalling a dso to xml """
        dst1 = DST(subject="testSubject1", predicate="testPredicate1", object="testObject1", literal=None, literal_type=None)
        dst2 = DST(subject="testSubject2", predicate="testPredicate2", object=None, literal="testLiteral2", literal_type="String")
        dst_list = [dst1, dst2]
        dso = DSO()
        dso.add_dsts(dst_list)
        expected_xml = """<dso><dst><subject>testSubject1</subject><predicate>testPredicate1</predicate><object>testObject1</object><literal></literal><literalType></literalType></dst><dst><subject>testSubject2</subject><predicate>testPredicate2</predicate><object></object><literal>testLiteral2</literal><literalType>String</literalType></dst></dso>"""
        if dso.to_xml() == expected_xml:
            assert True
        else:
            print dso.to_xml()
            print expected_xml
            self.fail("Output XML is incorrect")
    
    def test_unmarshal(self):
        """ Tests unmarshalling a xml to a dso """
        subject1 = "testSubject1"
        predicate1 = "testPredicate1"
        object1 = "testObject1"
        subject2 = "testSubject2"
        predicate2 = "testPredicate2"
        literal2 = "testLiteral2"
        literal_type2 = "testLiteralType2"
        xml = "<dso>"
        xml += "<dst>"
        xml += "<subject>" + subject1 + "</subject>"
        xml += "<predicate>" + predicate1 + "</predicate>"
        xml += "<object>" + object1 + "</object>"
        xml += "</dst>"
        xml += "<dst>"
        xml += "<subject>" + subject2 + "</subject>"
        xml += "<predicate>" + predicate2 + "</predicate>"
        xml += "<literal>" + literal2 + "</literal>"
        xml += "<literalType>" + literal_type2 + "</literalType>"
        xml += "</dst>"
        xml += "</dso>"
        
        dso = DSO(xml_string=xml)
        assert len(dso.dsts) == 2
        dsts = dso.dsts
        dst1 = dsts[0]
        dst2 = dsts[1]
        assert dst1.subject == subject1
        assert dst1.predicate == predicate1
        assert dst1.object == object1
        assert dst1.literal == None
        assert dst1.literal_type == None
        assert dst2.subject == subject2
        assert dst2.predicate == predicate2
        assert dst2.object == None
        assert dst2.literal == literal2
        assert dst2.literal_type == literal_type2        

    def test_get_dsts_case_1(self):
        """ Tests getting dsts """
        dst1 = DST(subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(subject="TestSubject2", predicate="TestPredicate2", literal="456")        
        dso = DSO(dsts=set([dst1, dst2]))
        dsts = dso.get_dsts()
        if len(dsts) == 2:
            assert True
        else:
            self.fail("Adding dsts failed")
                    
    def test_add_dsts_case_1(self):
        """ Tests adding dsts """
        dso = DSO()
        dst1 = DST(subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dso.add_dsts([dst1, dst2])
        dsts = dso.get_dsts()
        if len(dsts) == 2:
            assert True
        else:
            self.fail("Adding dsts failed")
    
    def test_add_dsts_case_2(self):
        """ Tests updating dst """
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dso = DSO(dsts=set([dst1, dst2]))
        updated_test_subject = "UpdatedTestSubject"
        dst1.subject = updated_test_subject
        dso.add_dsts([dst1])
        dsts = dso.get_dsts()
        if len(dsts) != 2:
            self.fail("Should return 2 dsts")

        for dst in dsts:
            if dst.id == 1 and dst.subject != updated_test_subject:
                self.fail("Subject field should have been updated")
                
        # pass if the above two conditions passed
        assert True
            
    def test_add_dsts_case_3(self):
        """ Tests updating a dst that does not exist in dso """
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dso = DSO(dsts=set([dst1, dst2]))
        try:
            updated_test_subject = "UpdatedTestSubject"
            dst2.subject = updated_test_subject
            dst3 = DST(id=3, subject="TestSubject1", predicate="TestPredicate2", literal="456")
            dso.add_dsts([dst2, dst3])
            self.fail('Trying to update a dst that does not exist in dso should not be allowed')
        except DSOUpdateException:
            dsts = dso.get_dsts()
            # make sure that no dsts were added
            if len(dsts) != 2:
                self.fail("Should not have added or removed any dsts if any update has failed")
            
            for dst in dsts:
                if dst.id == 2 and dst.subject != updated_test_subject:
                    self.fail('Subject field should not have been updated')
            
            assert True
   
    def test_remove_dsts_case_1(self):
        """ Tests removing dsts """
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dst3 = DST(id=3, subject="TestSubject3", predicate="TestPredicate3", literal="789")
        dso = DSO(dsts=set([dst1, dst2, dst3]))
        dso.remove_dsts([dst1, dst2])
        dsts = dso.get_dsts()
        if len(dsts) == 1 and dsts[0].id == 3:
            assert True
        else:
            self.fail('removing of dsts failed')
       
    def test_remove_dsts_case_2(self):
        """ Tests removing dst which does not exists in dso """
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dso = DSO(dsts=set([dst1, dst2]))
        dst3 = DST(id=3, subject="TestSubject3", predicate="TestPredicate3", literal="789")
        try:
            dso.remove_dsts([dst2, dst3])
            self.fail('Should not be able to remove a dst that does not belong to the dso')
        except DSOUpdateException:
            dsts = dso.get_dsts()
            # make sure that no dsts were added
            if len(dsts) != 2:
                self.fail("Should not have added or removed any dsts if any update has failed")

            assert True

    def test_is_new_case_1(self):
        """ Tests that new dsos can be detected """
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dso = DSO(dsts=set([dst1, dst2]))
        if dso.is_new():
            assert True
        else:
            self.fail('dso should be new')
            
    def test_is_new_case_2(self):
        """ Tests that not new dsos can be detected """
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dso = DSO(id=1, dsts=set([dst1, dst2]))
        if not dso.is_new():
            assert True
        else:
            self.fail('dso is not new')            
        
    def test_is_dsts_updated_case_1(self):
        """ Tests that updates to dsts can be detected """
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dso = DSO(id=1, dsts=set([dst1, dst2]))
        dst3 = DST(subject="TestSubject3", predicate="TestPredicate3", literal="789")
        dso.add_dsts([dst3])
        if dso.is_dsts_updated():
            assert True
        else:
            self.fail('Updated dsts not detected')
            
    def test_is_dsts_updated_case_2(self):
        """ Tests that NO updates to dsts can be detected """
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dso = DSO(id=1, dsts=set([dst1, dst2]))
        if not dso.is_dsts_updated():
            assert True
        else:
            self.fail('NO updates to dsts should be detected')
    
    def test_is_dsts_updated_case_3(self):
        """ Tests that updates return false for NEW dsos """
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dso = DSO(dsts=set([dst1, dst2]))
        if not dso.is_dsts_updated():
            assert True
        else:
            self.fail('NO updates to dsts should be detected as dso is NEW')
    
    def test_anonymous_reference_case_1(self):
        """ Tests dso gets the next highest anonymous reference """
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", object=100)
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", object=200)
        dso = DSO(dsts=set([dst1, dst2]))
        assert dso.get_next_anonymous_reference() == 201
        
    def test_anonymous_reference_case_2(self):
        """ Tests dso gets the next highest anonymous reference when there are no dsts with anonymous reference"""
        dst1 = DST(id=1, subject="TestSubject1", predicate="TestPredicate2", literal="123")
        dst2 = DST(id=2, subject="TestSubject2", predicate="TestPredicate2", literal="456")
        dso = DSO(dsts=set([dst1, dst2]))
        assert dso.get_next_anonymous_reference() == 1
    
    def test_anonymous_reference_case_3(self):
        """ Tests dso gets the next highest anonymous reference when there are no dsts """
        dso = DSO()
        assert dso.get_next_anonymous_reference() == 1
    
if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.test_to_xml']
    unittest.main()